package compilers.condition;

import java.io.BufferedWriter;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;

import org.antlr.runtime.Token;

import compilers.Node;
import compilers.node.Identifier;
import compilers.output.ErrorOutput;
import compilers.table.MemScope;
import compilers.types.Type;

public class Scanf extends Factor {

	String fString;
	Vector<Identifier> fIdentifiers = new Vector<Identifier>();
	
	public Scanf(String fString) {
		super();
		this.fString = fString;
	}
	
	public void checkParameters(Token token, boolean included) {
		if	(!included) {
			new ErrorOutput(token,"Stdio not included.");
		}
		int count = 0;
		for (int i = 0; i < fString.length(); i++) {
			if (fString.charAt(i) == '%') {
				count++;
			}
		}
		if	(count != fIdentifiers.size()) {
			new ErrorOutput(token, "Scanf wrong paramter count.");
		}
		
	}
	
	public Type compute() {
		return null;
	}

	public void addIdentifier(Identifier fIdentifier) {
		fIdentifiers.add(fIdentifier);
	}

	public void print(int tab) {
		for (int i=1;i<=tab;i++){System.out.print("\t");}System.out.print("|-");
		System.out.println("Scanf (" + fString + ")");
		Enumeration<Identifier> enumeration = fIdentifiers.elements();
		while(enumeration.hasMoreElements()){
			((Node) enumeration.nextElement()).print(tab+1);
		}  
	}
	
	public void addArrayMemory(int index, MemScope scope, Vector<Integer> set, Identifier ident, BufferedWriter writer) throws IOException {
		Vector<Integer> ind = ident.getIndices(null);
		if (index < ind.size()) {
			for (int i = 0; i < ind.get(index).intValue(); i++) {
				set.set(index, i);
				addArrayMemory((index+1), scope, set, ident, writer);
			}
		} else {
			char c[] = ident.getfIdentifier().toCharArray();
			String n = "";
			for (int i = 0; i < c.length; i++) {
				if (c[i] == '[') {
					n = ident.getfIdentifier().substring(0, i);
					break;
				}
			}
			//int depth = scope.getDepth(ident.getfIdentifier(), 0);
			for (int i = 0; i < set.size(); i++) {
				n += "[" + set.get(i).intValue() + "]";
			}
			scope.add(n);
			writer.write("ldc c 0\n");
			//writer.write("str c " + depth + " " + scope.get(n) + "\n");
		}
	}

	public void generate(BufferedWriter writer, MemScope scope) throws IOException {
		int count = 0;
		char c[] = fString.toCharArray();

		
		for (int i = 0; i < fIdentifiers.size(); i++) {
			if ((fIdentifiers.get(count).getIndices(null).isEmpty()) && (scope.getArray(fIdentifiers.get(count).getfIdentifier()) != null)) {
				int total = 1;
				Vector<Integer> indices = scope.getArray(fIdentifiers.get(count).getfIdentifier()).getIndices(null);
				for (int k = 0; k < indices.size(); k++) {
					total *= indices.get(k);
				}
				writer.write("ssp " + (10+total) + "\n");
			}
		}
		
		
		for (int i = 0; i < c.length; i++) {
			if (c[i] == '%') {
				i++;
				while ((i < c.length) && (Character.isDigit(c[i]))) {
					i++;
				}
				if (c[i] == 's') {
					if ((fIdentifiers.get(count).getIndices(null).isEmpty()) && (scope.getArray(fIdentifiers.get(count).getfIdentifier()) != null)) {
						String firstElement = fIdentifiers.get(count).getfIdentifier();
						for (int k = 0; k < scope.getArray(fIdentifiers.get(count).getfIdentifier()).getIndices(null).size(); k++) {
							firstElement += "[0]";
						}
						
						Vector<Integer> set = new Vector<Integer>();
						Vector<Integer> ind = scope.getArray(fIdentifiers.get(count).getfIdentifier()).getIndices(null);
						for (int a = 0; a < ind.size(); a++) {
							set.add(0);
						}
						addArrayMemory(0, scope, set, scope.getArray(fIdentifiers.get(count).getfIdentifier()), writer);
						
						//System.out.println("first element " + firstElement + " address: " + scope.get(firstElement));
						
						String uniqueLabel = scope.getUniqueLabel();
						
						writer.write("ldc i " + scope.get(firstElement) + "\n");
						writer.write("conv i a\n");
						writer.write("scanf" + uniqueLabel+ ":\n");
						writer.write("dpl a\n");
						writer.write("dpl a\n");
						writer.write("in c\n");
						writer.write("dpl c\n");
						writer.write("ldc c 27\n");
						writer.write("neq c\n");
						writer.write("fjp scanf_end" + uniqueLabel+ "\n");
						writer.write("sto c\n");
						writer.write("conv a i\n");
						writer.write("ldc i 1\n");
						writer.write("add i\n");
						writer.write("conv i a\n");
						writer.write("ujp scanf" + uniqueLabel+ "\n");
						writer.write("scanf_end" + uniqueLabel+ ":\n");
						count++;
					} else {
						System.out.println("scanf parameter is no array ! -> use 'c' instead ?");
					}
				} else if (c[i] == 'c') {
					writer.write("in c\n");
					writer.write("str c 0 " + scope.get(fIdentifiers.get(count).getfIdentifier()) + "\n");
					count++;
				} else if (c[i] == 'f') {
					writer.write("in r\n");
					writer.write("str r 0 " + scope.get(fIdentifiers.get(count).getfIdentifier()) + "\n");
					count++;
				} else {
					writer.write("in i\n");
					writer.write("str i 0 " + scope.get(fIdentifiers.get(count).getfIdentifier()) + "\n");
					count++;
				}
			} else if ((c[i] == '\\') && (c[i+1] == 'n')) {
				writer.write("ldc c 10\n");
				writer.write("out c\n");
				i++;
			} else {
				writer.write("ldc c '" + c[i] + "'\n");
				writer.write("out c\n");
			}
		}
		
		// return number of chars
		if (this.getfRes() != null) {
			writer.write("ldc " + this.getfRes().getPType() + " " + c.length + "\n");
		} 	
	}

}
